

package commandz.cfg;

import commandz.var.Variable;
import java.io.*;
import java.util.*;


/**
 *  Takes care of (de)serialization of user-accessible settings.
 *
 *  Settings are formed by pairs of unique identifiers and Variable-objects.
 *
 *  @see Variable
 */
public class Configuration
{
    /*
     *  Associative storage for the settings.
     */
    private Map<String, Variable> settings;


    /**
     *  Initializes a new Configuration.
     */
    public Configuration()
    {
        settings = new TreeMap<String, Variable>();
    }


    /**
     *  Adds a setting to this Configuration.
     *
     *  @param key      A (unique) value that identifies the new setting.
     *  @param property A Variable-object for storage of the property of the setting.
     */
    public void add(final String key, final Variable property)
    {
        settings.put(key, property);
    }


    /**
     *  Removes the specified setting from this Configuration.
     *
     *  @param key A value that identifies the setting to be removed.
     *
     *  @return Whether the setting is removed or not.
     */
    public boolean remove(final String key)
    {
        Variable var = settings.remove(key);
        return var != null;
    }


    /**
     *  Removes all settings from this Configuration.
     */
    public void clear()
    {
        settings.clear();
    }


    /**
     *  Returns the value of a specified setting.
     *
     *  @param key A value that identifies the setting.
     *
     *  @return The requested Variable-object or null if the
     *          setting does not exists.
     */
    public Variable get(final String key)
    {
        return settings.get(key);
    }


    /**
     *  Updates a given setting with the specified value.
     *
     *  @param key   A value that identifies the setting.
     *  @param value The value to set.
     *
     *  @return Whether the setting exists and the value could be set or not.
     */
    public boolean set(final String key, final String value)
    {
        Variable var = get(key);
        return var != null && var.parse(value);
    }


    /**
     *  Returns all settings of this Configuration.
     *
     *  @return A Collection of Variable-objects.
     */
    public Collection<Variable> getSettings()
    {
        return settings.values();
    }

    
    /**
     *  Reads the settings of this Configuration from a specified file.
     *
     *  @param filename The name of a file to read from.
     *
     *  @throws IOException if something went wrong.
     */
    public void read(String filename) throws IOException
    {
        read(new FileInputStream(filename));
    }


    /**
     *  Reads the settings of this Configuration from a specified stream.
     *
     *  @param source Any InputStream that is ready to read from.
     *
     *  @throws IOException if something went wrong.
     */
    public void read(InputStream source) throws IOException
    {
        Reader input = new InputStreamReader(source);
        BufferedReader buffer = new BufferedReader(input);

        while (true)  // read a setting..
        {
            String line = buffer.readLine();

            if (line == null)  // end of input?
                break;

            String tokens[] = line.split("\\s*=\\s*");

            if (tokens.length != 2)  // parse error?
                continue;

            set(tokens[0], tokens[1]);
        }
    }
    

    /**
     *  Writes the settings of this Configuration to a specified file.
     *
     *  @param filename The name of a file to write to.
     *
     *  @throws IOException if something went wrong.
     */
    public void write(String filename) throws IOException
    {
        write(new FileOutputStream(filename));
    }


    /**
     *  Writes the settings of this Configuration to a specified stream.
     *
     *  @param destination Any OutputStream that is ready to write to.
     *
     *  @throws IOException if something went wrong.
     */
    public void write(OutputStream destination) throws IOException
    {
        Writer output = new OutputStreamWriter(destination);
        PrintWriter buffer = new PrintWriter(output);

        for (Map.Entry<String, Variable> entry : settings.entrySet())
        {
            String key = entry.getKey();
            Variable var = entry.getValue();
            buffer.printf("%s = %s\n", key, var.format());
        }

        buffer.flush();  // Assure the file gets its content.
    }

}
